﻿Imports System
Imports System.IO
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.Design
Imports System.Globalization
Imports System.Xml
Imports System.Xml.XPath
Imports System.Text.RegularExpressions

Namespace DotNetNuke.Modules.ActiveForums.Controls
    <SupportsEventValidation()> _
        <DefaultProperty("Text"), Designer("DotNetNuke.Modules.ActiveForums.Controls.ActiveCallbackDesigner"), ParseChildren(True, ""), ToolboxData("<{0}:Callback runat=server></{0}:Callback>")> _
        Public Class Callback
        Inherits WebControl

#Region "Declarations"

        Private _content As CallBackContent
        Private _loadingtemplate As ClientTemplate
        Private _debug As Boolean = False
        Private _loaded As Boolean = False
        Private _isCallback As Boolean = False
        Private _previouscontent As CallBackContent
        Private _refreshInterval As Integer = Nothing
        Private _parameter As String = ""
        Private _resourceFile As String = ""
        Public Event Callback As CallbackEventHandler
        Delegate Sub CallbackEventHandler(ByVal sender As Object, ByVal e As CallBackEventArgs)
        Private _PostURL As String = ""
        Private _token As String = String.Empty
        Private _validState As Integer = 0 '-1 = don't process, 0 = initial load, 1 = process

#End Region

#Region "Properties"

        <Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property Debug() As Boolean
            Get

                Return _debug
            End Get

            Set(ByVal Value As Boolean)
                _debug = Value
            End Set
        End Property
        <Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property RefreshInterval() As Integer
            Get
                Return _refreshInterval
            End Get

            Set(ByVal Value As Integer)
                _refreshInterval = Value
            End Set
        End Property
        <Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property Parameter() As String
            Get
                Return _parameter
            End Get

            Set(ByVal Value As String)
                _parameter = Value
            End Set
        End Property
        ''' <summary>
        ''' Javascript function to fire on Callback Complete
        ''' Example without params: OnCallbackComplete="foo"
        ''' Example with params: OnCallbackComplete="function(){foo(params);}"
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property OnCallbackComplete() As String
            Get
                Dim s As String = CStr(ViewState("OnCallbackComplete"))
                If s Is Nothing Then
                    Return "null"
                Else
                    Return s
                End If
            End Get

            Set(ByVal Value As String)
                ViewState("OnCallbackComplete") = Value
            End Set
        End Property
        <Description("Initial content to render."), DefaultValue(Nothing, ""), Browsable(False), NotifyParentProperty(True), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)> _
        Public Property Content() As CallBackContent
            Get
                EnsureChildControls()
                Return _content
            End Get
            Set(ByVal Value As CallBackContent)
                _content = Value
            End Set
        End Property
        <Description("Loading Template during Callback"), PersistenceMode(PersistenceMode.InnerProperty)> _
        Public Property LoadingTemplate() As ClientTemplate
            Get
                Return _loadingtemplate
            End Get
            Set(ByVal Value As ClientTemplate)
                _loadingtemplate = Value
            End Set
        End Property
        Public Overrides ReadOnly Property Controls() As System.Web.UI.ControlCollection
            Get
                EnsureChildControls()
                Return MyBase.Controls
            End Get
        End Property
        <Description("Whether we are currently in a callback request."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(False)> _
        Public ReadOnly Property IsCallback() As Boolean
            Get
                If Context IsNot Nothing AndAlso Context.Request IsNot Nothing Then
                    Dim sId As String = ClientID
                    If Not String.IsNullOrEmpty(ForceId) Then
                        sId = ForceId
                    End If
                    If Not Context.Request.Params(String.Format("amCB_{0}", sId)) Is Nothing Then
                        _isCallback = True
                    Else
                        _isCallback = False
                    End If
                End If
                Return _isCallback
            End Get
        End Property
        Public Property ResourceFile() As String
            Get
                Return _resourceFile
            End Get
            Set(ByVal value As String)
                _resourceFile = value
            End Set
        End Property
        Property PostURL() As String
            Get
                Return _PostURL
            End Get
            Set(ByVal value As String)
                _PostURL = value
            End Set
        End Property
        Private _forceId As String = String.Empty
        Public Property ForceId() As String
            Get
                Return _forceId
            End Get
            Set(ByVal value As String)
                _forceId = value
            End Set
        End Property

#End Region

#Region "Events/Subs"

        Private Sub Callback_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            If Context Is Nothing OrElse Page Is Nothing Then
                Return
            End If
            If Content IsNot Nothing Then
                'Try
                Me.Controls.Add(Content)
                'Catch ex As Exception

                'End Try

            End If
        End Sub
        Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
            If Enabled Then
                'Dim sID As String = Me.ClientID
                'Dim args() As String = GetArgs()
                'If Not args Is Nothing Then
                '    If args.Length > 0 Then
                '        Me.handleCB(args)
                '        Return
                '    End If
                'End If
                'output = New HtmlTextWriter(output, String.Empty)
                'AddAttributesToRender(output)
                'output.RenderBeginTag(HtmlTextWriterTag.Div)
                'If Not Content Is Nothing Then
                '    Content.RenderControl(output)
                'End If
                'output.RenderEndTag()
                Dim sID As String = Me.ClientID
                If Not String.IsNullOrEmpty(ForceId) Then
                    sID = ForceId
                End If
                Dim args() As String = GetArgs()
                If Not args Is Nothing Then
                    If args.Length > 0 Then
                        Me.handleCB(args)
                        Return
                    End If
                End If
                output = New HtmlTextWriter(output, String.Empty)
                If String.IsNullOrEmpty(ForceId) Then
                    AddAttributesToRender(output)
                Else
                    output.AddAttribute("id", sID)
                End If

                ' Me.ID = sID

                output.RenderBeginTag(HtmlTextWriterTag.Div)
                If Not Content Is Nothing Then
                    Content.RenderControl(output)
                End If
                output.RenderEndTag()
                If Not Page Is Nothing And Not Context Is Nothing And Not Context.Request Is Nothing And Not Context.Request.Form("amCB_" & sID) Is Nothing And Not Context.Request.Form("amCB_" & sID) = "" Then
                    Me.OnCallback(New CallBackEventArgs(output, Context.Request.Form("amCB_" & sID)))
                End If
                If HttpContext.Current.Request.Params("amcbdebug") = "true" Or HttpContext.Current.Request.Params("amdebug") = "true" Then
                    Me.Debug = True
                End If

                Dim str As New StringBuilder
                str.Append("<script type=""text/javascript"">")
                If Not OnCallbackComplete Is Nothing Then
                    str.Append("window.objCB.prototype.CBC_" & sID & "=" & OnCallbackComplete & ";")
                End If
                If Not Me.LoadingTemplate Is Nothing Then
                    str.Append("window.objCB.prototype.LT_" & sID & "='" & LoadingTemplate.Text.Replace("\r", "").Replace("'", "\\'").Replace("\n", "").Replace(Chr(10), "").Replace(Chr(13), "") & "';")
                End If
                str.AppendFormat("window.{0}=new objCB('{0}');", sID)
                str.Append(sID & ".Debug=" & Debug.ToString.ToLower & ";")
                Dim URL As String = PostURL
                If URL = "" Then
                    '  URL = GetResponseUrl(Context)
                End If
                'If URL.Contains("/404.aspx?404;") Then
                '    URL = URL.Replace("/404.aspx?404;", String.Empty)
                'End If
                If Not String.IsNullOrEmpty(URL) Then
                    URL = XSSFilter(URL)
                    str.Append(sID & ".Location='" & URL.Replace("'", "\\'").Replace(";", String.Empty) & "';")
                End If
                str.Append(sID & ".Parameter='" & Parameter & "';")
                If Not Me.RefreshInterval = Nothing Then
                    str.AppendFormat("setInterval('{0}.Callback({0}.Parameter)',{1});", sID, RefreshInterval)
                End If
                str.Append("</script>")
                output.Write(str.ToString())
            End If


        End Sub
        Public Function XSSFilter(ByVal sText As String) As String
            sText = HttpContext.Current.Server.UrlDecode(sText)
            Dim pattern As String = "<script.*/*>|</script>|<[a-zA-Z][^>]*=['""]+javascript:\w+.*['""]+>|<\w+[^>]*\son\w+=.*[ /]*>"
            sText = Regex.Replace(sText, pattern, String.Empty, RegexOptions.IgnoreCase)
            sText = sText.Replace("-->", String.Empty)
            sText = sText.Replace("<!--", String.Empty)
            Return sText
        End Function
        Protected Overrides Sub CreateChildControls()
            If Content IsNot Nothing Then
                'Try
                Controls.Clear()
                Me.Controls.Add(Content)
                'Catch ex As Exception

                'End Try

            End If
            'ChildControlsCreated = True
        End Sub
        Private Sub handleCB(ByVal args As String())
            Try
                If _validState = 1 Then
                    Using strWriter As New StringWriter()
                        Using oWriter As New HtmlTextWriter(strWriter, String.Empty)
                            Dim oArgs As New CallBackEventArgs(oWriter) With {.Parameter = args(0), .Parameters = args}
                            Me.OnCallback(oArgs)
                            oWriter.Close()
                        End Using
                        Context.Response.Clear()
                        Context.Response.ContentType = "text/xml"
                        Context.Response.Write("<CallbackData><![CDATA[")
                        Dim sTemp As String = strWriter.ToString
                        sTemp = sTemp.Replace("//<![CDATA[", String.Empty)
                        sTemp = sTemp.Replace("//]]>", String.Empty)
                        Context.Response.Write(sTemp)
                    End Using
                    Context.Response.Write("]]></CallbackData>")
                    'Context.Response.Flush()

                    Context.Response.End()


                    'HttpContext.Current.ApplicationInstance.CompleteRequest()
                ElseIf _validState = -1 Then
                    Throw New Exception("Incomplete Request")
                End If
                'Dim strWriter As New StringWriter()
                'Dim oWriter As New HtmlTextWriter(strWriter, String.Empty)
                'Dim oArgs As New CallBackEventArgs(oWriter)
                'oArgs.Parameter = args(0)
                'oArgs.Parameters = args
                'Me.OnCallback(oArgs)
                'oWriter.Close()
                'Context.Response.Clear()
                'Context.Response.ContentType = "text/xml"
                'Context.Response.Write("<CallbackData><![CDATA[")
                'Dim sTemp As String = strWriter.ToString
                'sTemp = sTemp.Replace("//<![CDATA[", String.Empty)
                'sTemp = sTemp.Replace("//]]>", String.Empty)
                'Context.Response.Write(sTemp)
                'Context.Response.Write("]]></CallbackData>")
                ''Context.Response.Flush()
                'Context.Response.End()
                ''HttpContext.Current.ApplicationInstance.CompleteRequest()
            Catch ex As Exception
                If Not TypeOf (ex) Is Threading.ThreadAbortException Then
                    Context.Response.Clear()
                    Context.Response.ContentType = "text/xml"
                    Context.Response.Write("<CallbackError><![CDATA[" & ex.ToString & "]]></CallbackError>")
                    Context.Response.End()
                    'HttpContext.Current.ApplicationInstance.CompleteRequest()
                End If
            End Try
        End Sub
        Public Shared Function GetResponseUrl(ByVal oContext As HttpContext) As String
            Return oContext.Request.Url.Scheme & Uri.SchemeDelimiter & oContext.Request.Url.Host & (CType(IIf(oContext.Request.Url.IsDefaultPort, "", (":" & oContext.Request.Url.Port)), String)) & oContext.Response.ApplyAppPathModifier(oContext.Request.RawUrl)
        End Function
        'Private Function GetArgs() As String()
        '    Dim idname As String = "amCB_" & Me.ClientID
        '    Dim args() As String = Nothing
        '    If Not Context Is Nothing Then
        '        args = Context.Request.Params.GetValues(idname)
        '    End If
        '    If Not args Is Nothing Then
        '        For x As Integer = 0 To (args.Length - 1)
        '            args(x) = args(x).Replace("!AM#", "&").Replace("#AM!", "=").Replace("#MA!", "+")
        '        Next
        '    End If
        '    Return args
        'End Function
        Private Function GetArgs() As String()
            Dim sId As String = ClientID
            If Not String.IsNullOrEmpty(ForceId) Then
                sId = ForceId
            End If
            Dim idname As String = String.Format("amCB_{0}", sId)
            Dim args() As String = Nothing
            If Not Context Is Nothing Then
                Dim cName As String = "amcit"

                If Not HttpContext.Current.Request.Cookies(cName) Is Nothing Then

                    Dim token As String = HttpContext.Current.Request.Cookies(cName).Value
                    Dim tokenname As String = "hidreq"
                    Dim tokenvalue As String = String.Empty
                    If Not Context.Request.Params(tokenname) Is Nothing Then
                        tokenvalue = Context.Request.Params(tokenname)
                    End If
                    args = Context.Request.Params.GetValues(idname)
                    If Not args Is Nothing Then
                        If String.IsNullOrEmpty(tokenvalue) Then
                            _validState = -1
                            'Throw New Exception("Error validating request.")
                        Else
                            tokenvalue = tokenvalue.Replace("!AM#", "&").Replace("#AM!", "=").Replace("#MA!", "+")
                        End If
                        If Not token = tokenvalue Then
                            _validState = -1
                        Else
                            _validState = 1
                            For x As Integer = 0 To (args.Length - 1)
                                args(x) = args(x).Replace("!AM#", "&").Replace("#AM!", "=").Replace("#MA!", "+")
                            Next
                        End If




                    End If
                End If
            End If




            Return args
        End Function
        Private Sub OnCallback(ByVal e As CallBackEventArgs)
            RaiseEvent Callback(Me, e)
        End Sub
        Private Sub Callback_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not Page.ClientScript.IsClientScriptIncludeRegistered("AMCallback") Then
                Dim cbloaded As Boolean = False
                If Not HttpContext.Current.Items("cbld") Is Nothing Then
                    cbloaded = Boolean.Parse(HttpContext.Current.Items("cbld").ToString)
                End If
                If Not Me.IsCallback And Not Page.IsPostBack Then
                    If cbloaded = False And HttpContext.Current.Request.Params("hidreq") Is Nothing Then
                        Dim dnn As New DotNetNuke.Security.PortalSecurity
                        Dim ticket As String = dnn.Encrypt("afexp41", HttpContext.Current.Session.SessionID)

                        Dim myCookie As HttpCookie = New HttpCookie("amcit")
                        If Not HttpContext.Current.Request.Cookies("amcit") Is Nothing Then
                            HttpContext.Current.Response.Cookies("amcit").Value = ""
                            HttpContext.Current.Response.Cookies("amcit").Expires = Now.AddYears(-1)
                            HttpContext.Current.Response.Cookies("amcit").Domain = ""
                            HttpContext.Current.Response.Cookies("amcit").HttpOnly = True
                        End If
                        myCookie.HttpOnly = True
                        'myCookie.Path = "/"
                        'myCookie.Domain = HttpContext.Current.Request.Url.Host
                        myCookie.Expires = Now().AddHours(2)
                        myCookie.Value = ticket
                        HttpContext.Current.Response.Cookies.Add(myCookie)
                        Page.ClientScript.RegisterHiddenField("amcbid", ticket)
                        HttpContext.Current.Items.Add("cbld", "True")
                    End If
                End If
                Page.ClientScript.RegisterClientScriptInclude("AMCallback", Page.ClientScript.GetWebResourceUrl(Me.GetType, "cb.js"))
            End If
        End Sub
#End Region

    End Class
    Public Class CallBackEventArgs
        Inherits EventArgs

        Public Parameter As String
        Public Parameters() As String

        Public Output As HtmlTextWriter
        Friend Sub New(ByVal _writer As HtmlTextWriter)
            Output = _writer
        End Sub
        Friend Sub New(ByVal _writer As HtmlTextWriter, ByVal sParam As String)
            Output = _writer
            Parameter = sParam
        End Sub
    End Class
    <ToolboxItem(False)> _
      Public Class CallBackContent
        Inherits System.Web.UI.Control
    End Class
    <ToolboxItem(False)> _
    Public Class ClientTemplate
        Inherits System.Web.UI.Control
        <DefaultValue(""), Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Property Text() As String
            Get
                If Me.Controls.Count > 0 AndAlso TypeOf Me.Controls(0) Is LiteralControl Then
                    Return DirectCast(Me.Controls(0), LiteralControl).Text
                End If
                Return ""
            End Get
            Set(ByVal value As String)
                Me.Controls.Clear()
                Me.Controls.Add(New LiteralControl(value))
            End Set
        End Property
    End Class
    Public Class ActiveCallbackDesigner
        Inherits ControlDesigner

        Public Overrides Function GetDesignTimeHtml() As String
            Return "<div style=""font-family:tahoma;font-size:11px;"">Active Modules Callback Control</div>"
        End Function

    End Class
    Public Interface ICallback
        Sub Callback(ByVal sender As Object, ByVal e As Controls.CallBackEventArgs)


    End Interface
End Namespace
